package com.ruoyi.web.controller.business.order.factory;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ruoyi.business.base.JoSqlUtil;
import com.ruoyi.business.base.PageParam;
import com.ruoyi.business.core.service.DivisionsCodeService;
import com.ruoyi.business.customer.domain.JbCustomer;
import com.ruoyi.business.customer.service.JbCustomerService;
import com.ruoyi.business.goods.domain.JbCommodity;
import com.ruoyi.business.goods.domain.JbCommodityOfflinePrice;
import com.ruoyi.business.goods.service.JbCommodityOfflinePriceService;
import com.ruoyi.business.order.domain.JbApprovalLog;
import com.ruoyi.business.order.domain.JbOrder;
import com.ruoyi.business.order.domain.JbOrderCommodity;
import com.ruoyi.business.order.service.JbOrderCommodityService;
import com.ruoyi.business.order.service.JbOrderService;
import com.ruoyi.common.annotation.JoException;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.BusinessErrorEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.web.controller.business.customer.factory.JbCustormerFactory;
import com.ruoyi.web.controller.business.goods.factory.JbCommodityFactory;
import com.ruoyi.web.controller.business.order.vo.JbFnOrderAmountVO;
import com.ruoyi.web.controller.business.order.vo.JbOrderStatusEnum;
import com.ruoyi.web.controller.business.order.vo.JbOrderVO;
import com.ruoyi.web.controller.business.statistics.factory.JbCommissionFactory;
import com.ruoyi.web.controller.business.statistics.vo.JbCommissionVO;
import com.ruoyi.web.controller.business.statistics.vo.JbGrossProfitRateQueryVO;
import com.ruoyi.web.controller.flyflow.factory.FlyFlowFactory;
import com.ruoyi.web.controller.flyflow.util.FlyFlowUtil;
import com.ruoyi.web.controller.system.factory.SysDataScopeFactory;
import com.ruoyi.web.controller.thirdparty.factory.ThirdpartyExtendFactory;
import com.ruoyi.web.controller.thirdparty.factory.ThirdpartyOrderFactory;
import com.ruoyi.web.controller.tool.JoCodeUtils;
import com.ruoyi.web.core.JoController;
import com.ruoyi.web.core.tool.ColumnUtil;
import com.ruoyi.web.task.factory.TaskThirdpartyFactory;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 业务 订单 工厂
 *
 * @author Jyl
 */
@Log4j2
@Component
public class JbOrderFactory extends JoController
{

    @Getter
    @Autowired
    private JbOrderService service;
    @Autowired
    private JbOrderCommodityService jbOrderCommodityService;
    @Autowired
    private JbCommodityOfflinePriceService jbCommodityOfflinePriceService;
    @Autowired
    private JbApprovalLogFactory jbApprovalLogFactory;
    @Autowired
    private FlyFlowFactory factory;
    @Autowired
    private JbCustomerService jbCustomerService;
    @Autowired
    private JbCommodityFactory jbCommodityFactory;
    @Autowired
    private SysDataScopeFactory sysDataScopeFactory;
    @Autowired
    private JbCommissionFactory jbCommissionFactory;
    @Autowired
    private ThirdpartyOrderFactory thirdpartyOrderFactory;
    @Autowired
    private ThirdpartyExtendFactory thirdpartyExtendFactory;
    @Autowired
    private TaskThirdpartyFactory taskThirdpartyFactory;
    @Autowired
    private JbCustormerFactory jbCustormerFactory;
    @Autowired
    private DivisionsCodeService divisionsCodeService;

    /**
     * @param page    分页对象
     * @param jbOrder 业务对象
     * @return 查询对象
     */
    public Wrapper<JbOrder> getWrapper(PageParam page, JbOrder jbOrder)
    {
        List<Long> ids = sysDataScopeFactory.fnListDataScope(null);

        QueryWrapper<JbOrder> select = new QueryWrapper<>();
        select.lambda().eq(StringUtils.isNotEmpty(jbOrder.getOrderStatus()), JbOrder::getOrderStatus,
                        jbOrder.getOrderStatus())//订单状态
                .eq(StringUtils.isNotEmpty(jbOrder.getPaymentType()), JbOrder::getPaymentType,
                        jbOrder.getPaymentType())//付款方式
                .like(StringUtils.isNotEmpty(jbOrder.getBusinessManager()), JbOrder::getBusinessManager,
                        jbOrder.getBusinessManager())//业务经理
                .eq(ObjectUtil.isNotEmpty(jbOrder.getBusinessManagerId()), JbOrder::getBusinessManagerId,
                        jbOrder.getBusinessManagerId())//业务经理Id
                .eq(ObjectUtil.isNotEmpty(jbOrder.getCustomerId()), JbOrder::getCustomerId,
                        jbOrder.getCustomerId())//客户id
                .and(StringUtils.isNotEmpty(page.getKeyword()), e -> e
                        .like(JbOrder::getOrderNumber, page.getKeyword())
                        .or().like(JbOrder::getOrderTotalAmount, page.getKeyword())
                        .or().like(JbOrder::getCustomerName, page.getKeyword()))//关键字
                .eq(ObjectUtil.isNotEmpty(jbOrder.getCreateBy()), JbOrder::getCreateBy, jbOrder.getCreateBy())//创建人
                .eq(ObjectUtil.isNotEmpty(jbOrder.getBelongDepartment()), JbOrder::getBelongDepartment,
                        jbOrder.getBelongDepartment())//归属部门
                .ge(StringUtils.isNotBlank(page.getStartTime()), JbOrder::getCreateTime, page.getStartTimeBuilder())
                //创建时间
                .le(StringUtils.isNotBlank(page.getEndTime()), JbOrder::getCreateTime, page.getEndTimeBuilder())
                .eq(ObjectUtil.isNotEmpty(jbOrder.getCustomerId()), JbOrder::getCustomerId, jbOrder.getCustomerId())

                .in(ObjectUtil.isNotEmpty(ids), JbOrder::getCreateBy, ids);//数据权限过滤
        //客户id
        ;

        select.lambda().orderByDesc(ObjectUtil.isNotEmpty(jbOrder.getCreateBy()), JbOrder::getTopTime);
        select.orderBy(StringUtils.isNotEmpty(page.getSortKey()), page.isSort(), page.getSortKey());
        return select;
    }

    /**
     * 查询订单列表
     */
    public IPage<JbOrderVO> list(PageParam page, JbOrder jbOrder)
    {
        IPage<JbOrder> iPage = service.page(page.b(), getWrapper(page, jbOrder));

        List<Long> ids = new ArrayList<>();
        for (JbOrder record : iPage.getRecords())
        {
            ids.add(record.getBusinessManagerId());
        }

        IPage<JbOrderVO> iPageVO = new JoSqlUtil().jsonToEntity(iPage, JbOrderVO.class);
        if (!ids.isEmpty())
        {
            //查询业务经理头像
            Map<Long, SysUser> map = mapUser(ids);
            for (JbOrderVO record : iPageVO.getRecords())
            {
                if (map.containsKey(record.getBusinessManagerId()))
                    record.setBusinessManagerUrl(map.get(record.getBusinessManagerId()).getAvatar());
            }
        }

        return iPageVO;
    }

    /**
     * @param list 列表数据
     * @return 统计金额
     */
    public JSONObject fnAmount(List<JbOrderVO> list)
    {
        BigDecimal orderTotalAmount = BigDecimal.ZERO;
        BigDecimal realTotalAmount = BigDecimal.ZERO;
        for (JbOrderVO jbOrderVO : list)
        {
            orderTotalAmount = orderTotalAmount.add(jbOrderVO.getOrderTotalAmount());
            realTotalAmount = realTotalAmount.add(ObjectUtil.isNotEmpty(jbOrderVO.getRealOrderAmount()) ?
                    jbOrderVO.getRealOrderAmount() : BigDecimal.ZERO);
        }
        BigDecimal unRealTotalAmount = orderTotalAmount.subtract(realTotalAmount);

        return new JSONObject()
                .fluentPut("unRealTotalAmount", unRealTotalAmount)//未回款金额
                .fluentPut("realTotalAmount", realTotalAmount)//回款金额
                .fluentPut("orderTotalAmount", orderTotalAmount);//订单金额
    }

    /**
     * 获取订单详细信息
     */
    public JbOrderVO getInfoByNumber(String number)
    {
        JbOrder jbOrder = service.getOne(new LambdaQueryWrapper<JbOrder>().eq(JbOrder::getOrderNumber, number));
        return getJbOrderVO(jbOrder);
    }

    /**
     * 拼装 订单详情
     *
     * @param jbOrder 订单信息
     * @return 获取订单
     */
    private JbOrderVO getJbOrderVO(JbOrder jbOrder)
    {
        if (jbOrder == null) return null;
        JbOrderVO jbOrderVO = new JbOrderVO();
        BeanUtils.copyProperties(jbOrder, jbOrderVO);

        List<JbOrderCommodity> list = jbOrderCommodityService.list(new LambdaQueryWrapper<JbOrderCommodity>()
                .eq(JbOrderCommodity::getOrderId, jbOrder.getId())
        );
        jbOrderVO.setCommodityList(list);

        //关联客户信息
        JbCustomer jbCustomer = jbCustomerService.getById(jbOrder.getCustomerId());
        if (jbCustomer != null)
        {
            jbOrderVO.setCustomerPhone(jbCustomer.getPhoneNumber());
        }

        //草稿单子直接返回，不做余下金额计算
        if (jbOrder.getOrderStatus().equals(JbOrderStatusEnum.task0.getKey()))
        {
            return jbOrderVO;
        }

        //已付款金额
        BigDecimal yifukuan = jbOrderVO.getDepositAmount().add(jbOrderVO.getReceivedAmount())
                .setScale(2, RoundingMode.HALF_UP);
        //未付款金额
        BigDecimal weifukuan = jbOrderVO.getOrderTotalAmount().subtract(yifukuan)
                .setScale(2, RoundingMode.HALF_UP);

        BigDecimal wuliufei = BigDecimal.ZERO;
        JSONArray jsonArray = jbOrderVO.getYyLogisticsInformation();
        if (jsonArray != null && !jsonArray.isEmpty())
        {
            for (Object o : jsonArray)
            {
                JSONObject jsonObject = (JSONObject) o;
                BigDecimal feiyong = new BigDecimal(jsonObject.getString("wuliufeiyong"));
                wuliufei = wuliufei.add(feiyong);
            }
        }

        //是否有 小组组员/业务经理 以外的角色
        if (!otherRoleId(2L) && ObjectUtil.isNotEmpty(getRoleIds()))
        {
            jbOrderVO.setIsGrossProfitMarginShow(false);//以外的角色不能看毛利率，置空
        } else
        {
            jbOrderVO.setIsGrossProfitMarginShow(true);//以外的角色不能看毛利率，置空
        }

        jbOrderVO.setWuliufei(wuliufei);
        jbOrderVO.setWeifukuan(weifukuan);
        jbOrderVO.setYifukuan(yifukuan);

        return jbOrderVO;
    }

    /**
     * @param processNumber 流程编码
     * @return 订单对象
     */
    public JbOrderVO getInfoByProcessNumber(String processNumber)
    {
        JbOrder jbOrder = service.getOne(new LambdaQueryWrapper<JbOrder>()
                .eq(JbOrder::getProcessNumber, processNumber));
        if (jbOrder == null) return null;
        return getInfo(jbOrder.getId());
    }

    /**
     * 获取订单详细信息
     */
    public JbOrderVO getInfo(Long id)
    {
        JbOrder jbOrder = service.getById(id);
        return getJbOrderVO(jbOrder);
    }

    /**
     * 逻辑 处理客户信息
     *
     * @param jbOrder 订单对象
     * @return 执行结果
     */
    public boolean fnCustomer(JbOrder jbOrder)
    {
        Long id = jbOrder.getCustomerId();
        JbCustomer jbCustomer = jbCustomerService.getById(id);
        if (jbCustomer == null) return false;
        jbOrder.setCustomerType(jbCustomer.getCustomerType());
        jbOrder.setCustomerName(jbCustomer.getCustomerName());
        return true;
    }

    /**
     * 处理客户信息
     *
     * @param jbOrder 订单vo对象
     * @return 执行结果
     */
    public boolean fnCustomer(JbOrderVO jbOrder)
    {
        Long id = jbOrder.getCustomerId();
        JbCustomer jbCustomer = jbCustomerService.getById(id);
        if (jbCustomer == null) return false;
        //更新收货地址到客户信息内
        if (StringUtils.isBlank(jbCustomer.getDetailedAddress()))
        {
            jbCustormerFactory.updateAddress(
                    jbCustomer,
                    jbOrder.getShippingAddress(),
                    jbOrder.getAreaCodeAll());
        }
        jbOrder.setCustomerType(jbCustomer.getCustomerType());
        jbOrder.setCustomerName(jbCustomer.getCustomerName());
        return true;
    }

    /**
     * 编辑 订单
     *
     * @param jbOrderVO
     * @return
     */
    @Transactional
    public boolean edit(JbOrderVO jbOrderVO) throws InvocationTargetException, NoSuchMethodException,
            IllegalAccessException
    {
        List<JbOrderCommodity> commodities = jbOrderVO.getCommodityList();
        JbOrder jbOrder = new JbOrder();
        BeanUtils.copyProperties(jbOrderVO, jbOrder);

        if (!verifyAmount(jbOrderVO))
        {
            log.error("[{}]:{}", "订单编辑价格核算（edit.verifyAmount）", jbOrderVO.toString());
            throw new ServiceException("价格核算失败！");
        }

        //金额计算
        fnAmount(jbOrderVO);
        jbOrder.setHasGift(isHasGift(jbOrderVO));
        fnCustomer(jbOrder);
        boolean update = service.updateById(jbOrder);

        if (update && !commodities.isEmpty())
        {
            suCommodities(commodities, jbOrder);
        }

        return true;
    }

    /**
     * 新增编辑 处理关联订单商品的 逻辑
     *
     * @param commodities 订单商品项
     * @param jbOrder     订单
     * @return 执行结果
     */
    @Transactional
    public boolean suCommodities(List<JbOrderCommodity> commodities, JbOrder jbOrder)
    {
        List<Long> ids = new ArrayList<>();
        for (JbOrderCommodity commodity : commodities)
        {
            commodity.setOrderId(jbOrder.getId());
            commodity.setOrderNumber(jbOrder.getOrderNumber());
            if (commodity.getId() != null)
            {
                ids.add(commodity.getId());
            }
            commodity.setLogisticsWeight(commodity.getQuantity().multiply(commodity.getUnitContent()));
        }

        jbOrderCommodityService.remove(new LambdaQueryWrapper<JbOrderCommodity>()
                .notIn(!ids.isEmpty(), JbOrderCommodity::getId, ids)
                .eq(JbOrderCommodity::getOrderId, jbOrder.getId())
        );

        jbOrderCommodityService.saveOrUpdateBatch(commodities);
        return true;
    }

    /**
     * @param jbOrderVO 订单vo对象
     * @return 是否有赠品
     */
    private String isHasGift(JbOrderVO jbOrderVO)
    {
        String hasGift = "0";
        for (JbOrderCommodity commodity : jbOrderVO.getCommodityList())
            if (commodity.getType() == 1) hasGift = "1";
        return hasGift;
    }

    /**
     * 新增 草稿订单
     *
     * @param jbOrderVO
     * @return
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     */
    @Transactional
    public boolean draft(JbOrderVO jbOrderVO) throws InvocationTargetException,
            NoSuchMethodException,
            IllegalAccessException
    {
        jbOrderVO.setOrderStatus(JbOrderStatusEnum.task0.getKey());
        jbOrderVO.setOrderNumber(JoCodeUtils.CODE().ORDER);
        jbOrderVO.setId(null);

        JbOrder jbOrder = new JbOrder();
        BeanUtils.copyProperties(jbOrderVO, jbOrder);
        if (service.save(jbOrder) && !jbOrderVO.getCommodityList().isEmpty())
        {
            for (JbOrderCommodity commodity : jbOrderVO.getCommodityList())
            {
                commodity.setId(null);
                commodity.setOrderId(jbOrder.getId());
                commodity.setOrderNumber(jbOrder.getOrderNumber());
            }
            jbOrderCommodityService.saveBatch(jbOrderVO.getCommodityList());
        }
        if (jbOrder.getCustomerName() == null) return false;
        jbApprovalLogFactory.saveApprovalLog(
                "order",
                jbOrderVO.getOrderNumber(),
                "",
                "草稿",
                "保存草稿",
                "保存成功"
        );
        return true;
    }

    /**
     * 新增订单 逻辑
     *
     * @param jbOrderVO 订单vo对象
     * @return 订单对象
     */
    @Transactional
    public JbOrder addFn(JbOrderVO jbOrderVO)
    {
        List<JbOrderCommodity> commodities = jbOrderVO.getCommodityList();

        //校验订单价格
        if (!verifyAmount(jbOrderVO))
        {
            log.error("[{}]:{}", "订单新增价格核算（addFn.verifyAmount）", jbOrderVO.toString());
            throw new ServiceException("价格核算失败！");
        }

        //金额计算
        fnAmount(jbOrderVO);
        jbOrderVO.setHasGift(isHasGift(jbOrderVO));
        if (StrUtil.isEmpty(jbOrderVO.getOrderNumber()))
        {
            jbOrderVO.setOrderNumber(JoCodeUtils.CODE().ORDER);
        }

        JbOrder jbOrder = new JbOrder();
        BeanUtils.copyProperties(jbOrderVO, jbOrder);

        //处理订单商品
        if (service.saveOrUpdate(jbOrder) && !commodities.isEmpty())
        {
            suCommodities(commodities, jbOrder);
        }

        return jbOrder;
    }

    /**
     * 计算 物流重量级发货数量
     *
     * @param commodity 使用件价格
     */
    public void fnPiece(JbOrderCommodity commodity)
    {
        //获取原始商品
        JbCommodity jbCommodity = jbCommodityFactory.getInfo(commodity.getCommodityId());
        //更新物流重量
        commodity.setLogisticsWeight(jbCommodity.getUnitContent().multiply(commodity.getQuantity()));
        //更新发货箱数
        commodity.setNumberOfShippingBoxes(commodity.getQuantity().divide(BigDecimal.valueOf(jbCommodity.getCaseQuantity()), 3, RoundingMode.HALF_UP));
    }

    /**
     * 计算 物流重量级发货数量
     *
     * @param commodity 使用箱价格
     */
    public void fnBox(JbOrderCommodity commodity)
    {
        //获取原始商品
        JbCommodity jbCommodity = jbCommodityFactory.getInfo(commodity.getCommodityId());
        BigDecimal box = commodity.getQuantity().setScale(3, RoundingMode.HALF_UP);
        //更新物流重量
        commodity.setLogisticsWeight(BigDecimal.valueOf(jbCommodity.getCaseQuantity())
                .multiply(box).multiply(jbCommodity.getUnitContent()));
        //更新发货箱数
        commodity.setNumberOfShippingBoxes(box);
    }

    /**
     * 计算 物流重量级发货数量
     *
     * @param commodity 使用吨价格
     */
    public void fnTon(JbOrderCommodity commodity)
    {
        //获取原始商品
        JbCommodity jbCommodity = jbCommodityFactory.getInfo(commodity.getCommodityId());
        BigDecimal kg = commodity.getQuantity().multiply(new BigDecimal(1000.00));
        //更新物流重量
        commodity.setLogisticsWeight(kg);
        //更新发货箱数
        commodity.setNumberOfShippingBoxes(kg
                .divide(BigDecimal.valueOf(jbCommodity.getCaseQuantity()), 2, RoundingMode.HALF_UP)
                .divide(jbCommodity.getUnitContent(), 3, RoundingMode.HALF_UP)
        );
    }

    /**
     * 新增
     *
     * @param jbOrderVO
     * @return
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     */
    @Transactional
    public boolean add(JbOrderVO jbOrderVO) throws InvocationTargetException, NoSuchMethodException,
            IllegalAccessException
    {
        //订单业务状态
        jbOrderVO.setOrderStatus(JbOrderStatusEnum.task2.getKey());
        //赋值客户信息
        fnCustomer(jbOrderVO);
        //创建更新订单对象
        JbOrder jbOrder = addFn(jbOrderVO);
        if (jbOrder == null)
        {
            throw new ServiceException("提交订单执行失败");
        }
        //创建工作流
        startProcess(jbOrder);
        return true;
    }

    /**
     * 更新 流程编号
     *
     * @param processNumber 流程编号
     * @param id            业务主键
     */
    public void updateProcessNumber(String processNumber, Long id)
    {
        service.update(new LambdaUpdateWrapper<JbOrder>()
                .eq(JbOrder::getId, id)
                .set(JbOrder::getProcessNumber, processNumber));
    }

    /**
     * 启动流程实例
     *
     * @param jbOrder
     */
    @Transactional
    public void startProcess(JbOrder jbOrder)
    {
        //处理业务对象
        JSONObject order = JSONObject.parseObject(JSONObject.toJSONString(jbOrder));
        //获取流程
        JSONObject flow = FlyFlowUtil.getProcessInstance(factory.getProcessInstance(), "订单审批");
        //获取启动表单
        JSONObject flowInfo = factory.getProcessInstanceInfo(flow.getString("flowId"));

        //构建启动对象
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("uniqueId", flow.getString("uniqueId"));
        jsonObject.put("flowId", flow.getString("flowId"));
        jsonObject.put("paramMap", FlyFlowUtil.buildParamMap(flowInfo, order));
        JSONObject re = factory.processInstanceStart(jsonObject);
        if (!re.getBoolean("ok")) throw new RuntimeException("order process start fail");

        //更新流程单号
        updateProcessNumber(re.getString("data"), jbOrder.getId());
        jbApprovalLogFactory.saveApprovalLog(
                "order",
                jbOrder.getOrderNumber(),
                re.getString("data"),
                "发起审批",
                "提交订单",
                "提交成功"
        );
    }

    /**
     * 后台 校验价格
     */
    public boolean verifyAmount(JbOrderVO jbOrderVO)
    {
        List<JbOrderCommodity> list = jbOrderVO.getCommodityList();

        if (list.isEmpty()) return false;

        //金额计算，使用前台选取折算价格（箱价吨价都折算到单价），此逻辑废弃
//        verifyFactoryPrice(list, jbOrderVO.getPriceType());
        verifySubtotal(list, jbOrderVO);
        return true;
    }

    /**
     * 后台 计算销售数据
     *
     * @param list      商品&赠品
     * @param jbOrderVO 业务订单VO
     */
    public void verifySubtotal(List<JbOrderCommodity> list, JbOrderVO jbOrderVO)
    {
        if (ObjectUtil.isEmpty(jbOrderVO.getOrderTotalAmount()))
        {
            throw new ServiceException("订单金额不能为空");
        }
        //总计销售金额
        BigDecimal subtotal = BigDecimal.ZERO;
        //总计销售数量
        BigDecimal quantity = BigDecimal.ZERO;
        for (JbOrderCommodity jbCommodity : list)
        {
            //订单货物数量 (件)
            BigDecimal itemQuantity = jbCommodity.getQuantity();
            quantity = quantity.add(itemQuantity);

            //赠品数据处理逻辑
            if (jbCommodity.getType() == 1L)
            {
                jbCommodity.setSubtotal(BigDecimal.ZERO);//用友用数据 小计
                jbCommodity.setUnitPrice(BigDecimal.ZERO);//用友用数据 单价
                continue;
            }

            //小计销售金额
            BigDecimal unitPrice = jbCommodity.getUnitPrice();
            jbCommodity.setSubtotal(unitPrice.multiply(itemQuantity));
            subtotal = subtotal.add(jbCommodity.getSubtotal());
        }
        // 订单申报金额 - 订单实际金额 = 订单金额差值
        BigDecimal orderTotalAmount = jbOrderVO.getOrderTotalAmount();
        if (subtotal.compareTo(orderTotalAmount) >= 0)
        {//申报金额小于订单金额
            jbOrderVO.setDifferenceAmount(subtotal.subtract(orderTotalAmount)
                    .setScale(2, RoundingMode.HALF_UP)
            );
        } else
        {//申报金额大于订单金额
            jbOrderVO.setDifferenceAmount(orderTotalAmount.subtract(subtotal)
                    .setScale(2, RoundingMode.HALF_UP)
            );
        }

        //TODO 2025年3月4日 金额使用前端传递申报金额， 后台留存商品实际金额
        jbOrderVO.setDeclareAmount(subtotal);//留存实际金额
//        jbOrderVO.setOrderTotalAmount(subtotal);
        jbOrderVO.setRealOrderAmount(jbOrderVO.getOrderTotalAmount());//实付金额在 fnRealOrderAmount 会重新计算
        jbOrderVO.setQuantity(quantity);//没有使用的地方
    }

    /**
     * 逻辑 实付金额
     *
     * @param jbOrderVO
     * @return
     */
    private BigDecimal fnRealOrderAmount(JbOrderVO jbOrderVO)
    {
        BigDecimal realOrderAmount;
        switch (jbOrderVO.getPaymentType())
        {
            case "1001" -> realOrderAmount = jbOrderVO.getDepositAmount();
            case "1002" -> realOrderAmount = jbOrderVO.getOrderTotalAmount();
            default -> throw new ServiceException(BusinessErrorEnum.ABNORMAL_ORDER_PRODUCT_DATA);
        }
        return realOrderAmount;
    }

    /**
     * 逻辑 获取提成&毛利率对象
     *
     * @param jbOrderVO 订单对象
     * @return 提成&毛利率对象
     */
    private JbCommissionVO fnJbCommissionVO(JbOrderVO jbOrderVO)
    {
        JbGrossProfitRateQueryVO queryVO = new JbGrossProfitRateQueryVO();
        queryVO.setList(jbOrderVO.getCommodityList());
        queryVO.setAreaCode(jbOrderVO.getAreaCode());
        queryVO.setLogisticsId(jbOrderVO.getLogisticsId());
        queryVO.setOrderTotalAmount(jbOrderVO.getOrderTotalAmount());

        return jbCommissionFactory.fnRoyalties(queryVO);
    }

    /**
     * 计算 金额
     *
     * @param jbOrderVO
     */
    @JoException(message = "订单金额计算失败！商品缺少金额信息！")
    private void fnAmount(JbOrderVO jbOrderVO)
    {
        JbCommissionVO jbCommissionVO = fnJbCommissionVO(jbOrderVO);
        JbFnOrderAmountVO jbFnOrderAmountVO = JbFnOrderAmountVO.builder()
                .orderTotalAmount(jbOrderVO.getOrderTotalAmount())
                .realOrderAmount(fnRealOrderAmount(jbOrderVO))
                .depositAmount(jbOrderVO.getDepositAmount())
                .orderGrossProfitRate(jbCommissionVO.getInventoryGrossProfitRate())
                .receivedAmount(BigDecimal.ZERO)
                .commissionAmount(jbCommissionVO.getCommissionAmount())
                .build();

        log.info("[{}]:{}>>>{}", "订单金额计算(Order amount calculation)",
                jbCommissionVO.toString(),
                jbFnOrderAmountVO.toString());

        BeanUtils.copyProperties(jbFnOrderAmountVO, jbOrderVO);
    }

    /**
     * 财务审批通过发布用友销售订单
     *
     * @param jbOrder 订单对象
     * @return 执行结果
     */
    public Boolean fnThirdpartyOrderCreate(JbOrder jbOrder)
    {
        //财务审批通过发布用友销售订单，
        JbOrderVO jbOrderVO = getInfo(jbOrder.getId());
        JbCustomer jbCustomer = jbCustomerService.getById(jbOrderVO.getCustomerId());
        try
        {
            Boolean b = thirdpartyOrderFactory.fnCreate(jbOrderVO, jbCustomer);
            jbApprovalLogFactory.saveApprovalLog(
                    "order",
                    jbOrder.getOrderNumber(),
                    jbOrder.getProcessNumber(),
                    "同步用友",
                    b ? "同步用友，创建销售订货单" : "同步用友，创建销售订单失败，缺少业务id",
                    b ? "同步用友成功" : "同步用友失败"
            );
            //记录用友信息
            thirdpartyExtendFactory.add(jbOrder.getOrderNumber(), "CT", "orderNumber", b ? "create success" :
                    "create fail");
        } catch (IOException | InterruptedException e)
        {
            jbApprovalLogFactory.saveApprovalLog(
                    "order",
                    jbOrder.getOrderNumber(),
                    jbOrder.getProcessNumber(),
                    "同步用友",
                    "同步用友失败",
                    "同步用友失败"
            );
            //记录用友信息
            thirdpartyExtendFactory.add(jbOrder.getOrderNumber(), "CT", "orderNumber", "create abnormal");
            return false;
        }
        return true;
    }

    /**
     * 后台 重新赋值商品价格
     */
    @Deprecated
    public void verifyFactoryPrice(List<JbOrderCommodity> list, String priceType) throws InvocationTargetException,
            NoSuchMethodException, IllegalAccessException
    {
        //查询原始商品对象
        List<Long> ids = ids(list, ColumnUtil.F(JbOrderCommodity::getCommodityId));
        List<JbCommodityOfflinePrice> commodityOfflinePriceList =
                jbCommodityOfflinePriceService.selectCommodityList(ids);
        Map<Long, JbCommodityOfflinePrice> map = new HashMap<>();
        for (JbCommodityOfflinePrice jbCommodity : commodityOfflinePriceList)
            map.put(jbCommodity.getCommodityId(), jbCommodity);

        //价格核对
        for (JbOrderCommodity jbOrderCommodity : list)
            switch (priceType)
            {
                case "1001" ->
                        jbOrderCommodity.setFactoryPrice(map.get(jbOrderCommodity.getCommodityId()).getFactoryPrice());
                case "1002" ->
                        jbOrderCommodity.setFactoryPrice(map.get(jbOrderCommodity.getCommodityId()).getCustomPrice());
                case "1003" ->
                        jbOrderCommodity.setFactoryPrice(map.get(jbOrderCommodity.getCommodityId()).getTonPrice());
                default -> log.info("订单生成,商品({}),价格核算异常!!", jbOrderCommodity.getCommodityId());
            }
    }

    /**
     * 删除订单
     */
    public boolean remove(Long[] ids)
    {
        for (Long id : ids)
            jbOrderCommodityService.remove(new LambdaQueryWrapper<JbOrderCommodity>()
                    .eq(JbOrderCommodity::getOrderId, id));
        return service.removeByIds(Arrays.asList(ids));
    }

    /**
     * @param jbOrderVO 订单对象
     * @return 0否1是
     */
    public int toVoid(JbOrderVO jbOrderVO)
    {
        JbOrder jbOrder = service.getById(jbOrderVO.getId());
        if (jbOrder.getCreateBy() == getUserId())
        {
            service.update(new LambdaUpdateWrapper<JbOrder>()
                    .eq(JbOrder::getId, jbOrder.getId())
                    .set(JbOrder::getOrderStatus, JbOrderStatusEnum.task13.getKey())
            );
            return 1;
        }
        return 0;
    }

    /**
     * @param jbApprovalLog 审批日志
     * @return 执行结果
     */
    public int end(JbApprovalLog jbApprovalLog)
    {
        JbOrder jbOrder = service.getById(jbApprovalLog.getId());

        jbApprovalLogFactory.saveApprovalLog(
                "order",
                jbOrder.getOrderNumber(),
                "",
                "结束订单",
                jbApprovalLog.getOperationContent(),
                "已结束"
        );

        if (jbOrder.getCreateBy() == getUserId())
        {
            log.info("订单结束非法操作::操作人{},理应操作人{}", getUserId(), jbOrder.getCreateBy());
        }
        service.update(new LambdaUpdateWrapper<JbOrder>()
                .eq(JbOrder::getId, jbOrder.getId())
                .set(JbOrder::getOrderStatus, JbOrderStatusEnum.task13.getKey())
                .set(JbOrder::getIsBusinessEnd, true)
        );
        return 1;
    }

    /**
     * 查询集合
     *
     * @param status 订单状态
     * @return
     */
    public List<JbOrder> listByStatus(List<String> status)
    {
        return service.list(new LambdaQueryWrapper<JbOrder>()
                .ne(JbOrder::getYySaleOrderCode, "")
                .ne(JbOrder::getYySaleDeliveryCode, "")
                .in(JbOrder::getOrderStatus, status)
                .eq(JbOrder::isYyLogisticsIsAll, false)
                .eq(JbOrder::isYySaleDeliveryIsAll, true)
        );
    }

    /**
     * 逻辑 计价类型
     *
     * @param jbOrderVO 订单对象
     */
    public void fnPriceType(JbOrderVO jbOrderVO)
    {
        for (JbOrderCommodity commodity : jbOrderVO.getCommodityList())
        {
            if (ObjectUtil.isEmpty(commodity.getQuantity())
                || ObjectUtil.isEmpty(commodity.getUnitPrice())
            )
            {
                throw new ServiceException("订单商品价格计算，数据异常！");
            }
            switch (jbOrderVO.getPriceType())
            {
                case "1001" -> fnPiece(commodity);//出厂价、件
                case "1002" -> fnBox(commodity);//定制价、箱
                case "1003" -> fnTon(commodity);//吨价、吨
            }
        }
    }

    /**
     * 更新 业务状态
     *
     * @param id     主键
     * @param status 状态
     * @return 执行结果
     */
    public Boolean updateBusinessStatus(Long id, String status)
    {
        /*
         * 因工作流是先关闭流程，再变更状态:
         *  1.工作流先关闭流程，触发一次完结通知，且pass状态无法判别是否真实完结操作，
         *  2.工作流变更撤销状态，再触发一次完结通知，
         * 后续 工作流完结通知，工作流状态变更撤销通知 去除已撤销或已结束的
         */
        JbOrder jbOrder = service.getById(id);
        if (jbOrder.getOrderStatus().equals(JbOrderStatusEnum.task6.getKey())
            || jbOrder.getOrderStatus().equals(JbOrderStatusEnum.task5.getKey())
        )
        {
            return true;
        }
        service.update(new LambdaUpdateWrapper<JbOrder>()
                .eq(JbOrder::getId, id)
                .set(JbOrder::getOrderStatus, status)
                // 非通过流程，不做流程完成标识
                .set(status.equals(JbOrderStatusEnum.task1.getKey()), JbOrder::getIsProcessEnd, true)
        );

        try
        {
            taskThirdpartyFactory.sendThirdpartyPlaceAnOrder();
            log.info("订单完成通知，触发用友下单逻辑完成！！》》》》》》》");
        } catch (Exception e)
        {
            log.info("订单完成通知，触发用友下单逻辑异常！！>>>>>");
            log.error("订单完成通知，触发用友下单逻辑异常！！>>>>>{}:{}", e.getMessage(), e);
        }

        return true;
    }

    /**
     * 查询 未创建第三方订单的业务
     *
     * @return
     */
    public List<JbOrder> findNullYyOrderCode()
    {
        return service.list(new LambdaQueryWrapper<JbOrder>()
                .eq(JbOrder::getOrderStatus, JbOrderStatusEnum.task1.getKey())//流程审批通过的
                .isNull(JbOrder::getYySaleOrderCode)//还没有用友 销售订单号的
                .eq(JbOrder::isYySaleDeliveryIsAll, false)//是否已全部拉取
        );
    }

    /**
     * 查询 未全部获取第三方销货单的业务
     *
     * @return
     */
    public List<JbOrder> findNotYySaleDeliveryIsAll()
    {
        List<String> list = new ArrayList<>();
        list.add(JbOrderStatusEnum.task13.getKey());
        list.add(JbOrderStatusEnum.task11.getKey());
        return service.list(new LambdaQueryWrapper<JbOrder>()
                .isNotNull(JbOrder::getYySaleOrderCode)// 用友销售订单号不为空
                .notIn(JbOrder::getOrderStatus, list)// 过滤已结清及已结束

                .eq(JbOrder::isYySaleDeliveryIsAll, false)//是否已全部拉取
        );
        //.le(JbOrder::getYySalesOrderCount, 30)// 过滤过量查询
    }

    /**
     * 更新回款金额
     *
     * @param jbOrder 订单对象
     * @return
     */
    public boolean updateReceivedAmount(JbOrder jbOrder)
    {
        return service.update(new LambdaUpdateWrapper<JbOrder>()
                .eq(JbOrder::getId, jbOrder.getId())
                .set(JbOrder::getOrderStatus, jbOrder.getOrderStatus())
                .set(JbOrder::getReceivedAmount, jbOrder.getReceivedAmount())
        );
    }

    /**
     * 置顶
     *
     * @param jbOrderVO 订单VO
     * @return 执行结果
     */
    public boolean top(JbOrderVO jbOrderVO)
    {
        return service.update(new LambdaUpdateWrapper<JbOrder>()
                .eq(JbOrder::getId, jbOrderVO.getId())
                .set(JbOrder::getTopTime, new Date())
        );
    }

    /**
     * 取消置顶
     *
     * @param jbOrderVO 订单VO
     * @return 执行结果
     */
    public boolean unTop(JbOrderVO jbOrderVO)
    {
        return service.update(new LambdaUpdateWrapper<JbOrder>()
                .eq(JbOrder::getId, jbOrderVO.getId())
                .set(JbOrder::getTopTime, null)
        );
    }
}
